package com.bc.trade.channel.jwwxpay;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bc.common.PayType;
import com.bc.common.CommonEnum.OrderStatus;
import com.bc.common.CommonEnum.Resp;
import com.bc.common.message.AccountBalanceChangeResp;
import com.bc.common.message.AppidWxgjPayReq;
import com.bc.common.message.AppidWxgjPayResp;
import com.bc.common.message.DFReq;
import com.bc.common.message.DFResp;
import com.bc.common.message.WxgjClearingReq;
import com.bc.common.message.WxgjClearingResp;
import com.bc.trade.channel.IChannel;
import com.bc.trade.config.SystemConfig;
import com.bc.trade.message.QueryOrderResp;
import com.bc.trade.message.QuickPayReq;
import com.bc.trade.message.QuickPayResp;
import com.bc.trade.message.QuickPaySetReq;
import com.bc.trade.message.QuickPaySetResp;
import com.bc.trade.message.RefundReq;
import com.bc.trade.message.RefundResp;
import com.bc.trade.message.UnionPayReq;
import com.bc.trade.message.UnionPayResp;
import com.bc.trade.model.Channel;
import com.bc.trade.model.TradeOrder;
import com.bc.trade.model.TradeStrategy;
import com.bc.trade.model.WxClear;
import com.bc.trade.service.CalcFeeService;
import com.bc.trade.service.VirtualAccountService;
import com.fs.common.util.FSDate;
import com.fs.common.util.FSHttp;
import com.fs.common.util.FSLog;
import com.github.wxpay.sdk.WXPayUtil;

public class JWWxPayChannel implements IChannel {
	private final String APPID = SystemConfig.channelConfig.get("wxgj_appid");
	private final String MERCHANT_NO = SystemConfig.channelConfig.get("wxgj_merchant_no");
	private final String MERCHANT_KEY = SystemConfig.channelConfig.get("wxgj_merchant_ser");
	private final String TRADE_URL = SystemConfig.channelConfig.get("wxgj_create_url");
	private final String TRADE_URL_MICROPAY = SystemConfig.channelConfig.get("wxgj_micropay_url");
	private final String TRADE_QUERY_URL = SystemConfig.channelConfig.get("wxgj_query_url");
	private final String TRADE_NOTIFY_URL = SystemConfig.channelConfig.get("wxgj_notify_url");

	private final String TRADE_REFUND_URL = SystemConfig.channelConfig.get("wxgj_refund_url");
	private final String refund_notify = SystemConfig.channelConfig.get("wxgj_refund_notify");

	private  final String gethost = "www.qcurepay.com";
	private  final String getOpenidUrl_callbackPay = "http://" + gethost +"/trade/orderPublic?orderNo=";

	private final static String sslck = SystemConfig.config.get("file_center_path") + "/apiclient_cert.p12";

	private static VirtualAccountService accountService = new VirtualAccountService();

	@Override
	public QueryOrderResp query(TradeOrder order) throws Exception {
		// TODO Auto-generated method stub

		QueryOrderResp resp = new QueryOrderResp();
		TreeMap<String, String> map = new TreeMap<String, String>();
		map.put("appid", APPID);
		map.put("mch_id", MERCHANT_NO);
		map.put("sub_mch_id", order.getOtherMerchCode());
		map.put("out_trade_no", order.getOrderNo());
		map.put("nonce_str", WXPayUtil.generateNonceStr());
		map.put("sign", WXPayUtil.generateSignature(map, MERCHANT_KEY));

		try {
			String connext = WXPayUtil.mapToXml(map);
			FSLog.api.info("查询接口上送微信国际数据:" + connext);
			String result = FSHttp.postString(TRADE_QUERY_URL, connext);
			FSLog.api.info("查询接口微信国际响应数据:" + result);
			if (null == result) {// 链路超时
				resp.setOriginalRespCode(Resp.InProcess.getCode());
				resp.setOriginalRespMsg(Resp.InProcess.getMsg());
				resp.setCodeAndMsg(Resp.InProcess.getCode(), Resp.InProcess.getMsg());
				return resp;
			}

			Map<String, String> resmap = WXPayUtil.xmlToMap(result);

			String respCode = resmap.get("return_code");
			String result_code = resmap.get("result_code");
			String trade_state = resmap.get("trade_state");
			String time_end = resmap.get("time_end");
			String transaction_id = resmap.get("transaction_id");// 微信国际系统的订单号

			FSLog.api.info("微信国际查询通知订单：" + order.toString());

			if ("SUCCESS".equals(respCode) && "SUCCESS".equals(result_code) && "SUCCESS".equals(trade_state)) {
				String payTime = FSDate.formatDateTime(time_end, "yyyyMMddHHmmss", "yyyy-MM-dd HH:mm:ss");
				order.setPayTime(payTime);
				order.setChannelOrderNo(transaction_id);
				order.setRespCode(Resp.Success.getCode());
				order.setRespMsg(Resp.Success.getMsg());
				order.setOrderStatus(OrderStatus.Success.getValue());
				order.setSettleDate(Channel.findSettleDate(order));

				resp.setPayTime(payTime);
				resp.setOriginalRespCode(Resp.Success.getCode());
				resp.setOriginalRespMsg(Resp.Success.getMsg());
				resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
			} else if ("SUCCESS".equals(respCode) && "SUCCESS".equals(result_code)) {
				if ("NOTPAY".equals(trade_state) || "USERPAYING".equals(trade_state)) {
					order.setRespCode(Resp.InProcess.getCode());
					order.setRespMsg(resmap.get("err_code_des"));
					order.setOrderStatus(OrderStatus.InProcess.getValue());

					resp.setOriginalRespCode(Resp.InProcess.getCode());
					resp.setOriginalRespMsg(Resp.InProcess.getMsg());
					resp.setCodeAndMsg(Resp.InProcess.getCode(), Resp.InProcess.getMsg());
				} else {
					order.setRespCode(Resp.Fail.getCode());
					order.setRespMsg(trade_state + "," + resmap.get("err_code_des"));
					order.setOrderStatus(OrderStatus.Fail.getValue());

					resp.setOriginalRespCode(Resp.Fail.getCode());
					resp.setOriginalRespMsg(order.getRespMsg());
					resp.setCodeAndMsg(Resp.Fail.getCode(), Resp.Fail.getMsg());
				}
			} else {
				order.setRespCode(Resp.Fail.getCode());
				order.setRespMsg(resmap.get("return_msg") + "," + resmap.get("err_code_des"));
				order.setOrderStatus(OrderStatus.Fail.getValue());

				resp.setOriginalRespCode(Resp.Fail.getCode());
				resp.setOriginalRespMsg(order.getRespMsg());
				resp.setCodeAndMsg(Resp.Fail.getCode(), Resp.Fail.getMsg());

			}
			FSLog.api.info("微信国际处理完成订单：" + order.toString());
		} catch (Exception e) {
			FSLog.api.error("微信国际交易查询异常:" + e);
			resp.setCodeAndMsg(Resp.InProcess.getCode(), Resp.InProcess.getMsg());
		}
		return resp;
	}

	@Override
	public QueryOrderResp dfQuery(TradeOrder order) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public DFResp df(DFReq req, TradeOrder order) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public UnionPayResp unionpay(UnionPayReq req, TradeOrder order) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public QuickPaySetResp quickPaySet(QuickPaySetReq req, TradeOrder order) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public QuickPayResp quickPay(QuickPayReq req, TradeOrder order) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public AppidWxgjPayResp wxgjappidPayOrder(final TradeOrder order) throws Exception {
		AppidWxgjPayReq req = new AppidWxgjPayReq();
		req.setVersion("V1.0");
		req.setMerchCode(order.getMerchCode());
		req.setOrgCode(order.getOrgCode());
		req.setMerchOrderNo(order.getMerchOrderNo());
		req.setPayType(order.getPayType());

		AppidWxgjPayResp resp = new AppidWxgjPayResp(req);
		Map<String, String> paraMap = new HashMap<String, String>();
		paraMap.put("appid", APPID);
		if (order.getRemark() == null || 0 == order.getRemark().length()) {
			paraMap.put("body", order.getMerchOrderNo());
		} else {
			paraMap.put("body", order.getRemark());
		}

		if (null == order.getSubAppid() || 0 == order.getSubAppid().length()) {

		} else {
			paraMap.put("sub_appid", order.getSubAppid());
			paraMap.put("sub_openid", order.getSubOpenid());
		}

		paraMap.put("mch_id", MERCHANT_NO);
		paraMap.put("sub_mch_id", order.getOtherMerchCode());
		paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
		paraMap.put("out_trade_no", order.getOrderNo());// 订单号
		paraMap.put("spbill_create_ip", "127.0.0.1");
		paraMap.put("total_fee", order.getAmount()+"");
		paraMap.put("fee_type", order.getCoinType());
		paraMap.put("trade_type", "JSAPI");
		paraMap.put("openid", order.getOpenid());
		paraMap.put("notify_url", TRADE_NOTIFY_URL);// 此路径是微信服务器调用支付结果通知路径随意写
		String sign = WXPayUtil.generateSignature(paraMap, MERCHANT_KEY);
		paraMap.put("sign", sign);
		String xml = WXPayUtil.mapToXml(paraMap);
		String unifiedorder_url = TRADE_URL;
		String xmlStr = FSHttp.postString(unifiedorder_url, xml);
		FSLog.api.info("Send微信国际上游------->:" + unifiedorder_url + "\n" + xml + "\n");
		FSLog.api.info("recv微信国际上游------->:" + unifiedorder_url + "\n" + xmlStr + "\n");
		Map<String, String> mapstr = WXPayUtil.xmlToMap(xmlStr);
		String recvMysign = WXPayUtil.generateSignature(mapstr, MERCHANT_KEY);
		FSLog.api.info("返回的签名:" + mapstr.get("sign") + "," + "计算的签名:" + recvMysign);
		resp.setCodeAndMsg(Resp.InProcess.getCode(), Resp.InProcess.getMsg());
		resp.setPayInfo(JSONObject.toJSON(mapstr).toString());
		String prepay_id = null;
		if (mapstr != null && "SUCCESS".equals(mapstr.get("return_code"))
				&& "SUCCESS".equals(mapstr.get("result_code"))) {
			resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
			prepay_id = (String) mapstr.get("prepay_id");
			// 把数据传给前段页面， 执行微信的js调用即可调用 微信公众号支付的 支付页面s
			Map<String, String> payMap = new HashMap<String, String>();
			payMap.put("appId", APPID);
			payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
			payMap.put("nonceStr", WXPayUtil.generateNonceStr());
			payMap.put("signType", "MD5");
			payMap.put("package", "prepay_id=" + prepay_id);
			String paySign = WXPayUtil.generateSignature(payMap, MERCHANT_KEY);
			payMap.put("pg", "prepay_id=" + prepay_id);
			payMap.put("paySign", paySign);
			payMap.put("respCode", Resp.Success.getCode());
			payMap.put("coin_type", order.getCoinType());
			String pppJS = JSON.toJSONString(payMap);
			resp.setPayInfo(pppJS);
			resp.setOrderNo(order.getOrderNo());
		}else {
			resp.setRespMsg(mapstr.get("return_msg"));
		}
		return resp;
	}

	@Override
	public AppidWxgjPayResp wxgjappidPay(AppidWxgjPayReq req, TradeOrder order) throws Exception {
		if (PayType.WXGJPAY_QRCODE.equals(req.getPayType())) {
			return wxgjqrcode(req, order);// 动态二维码
		} else if (PayType.WXGJPAY_MICORPAY.equals(req.getPayType())) {
			return wxgjmiropay(req, order);// 扫码(刷卡)支付
		}
		AppidWxgjPayResp resp = new AppidWxgjPayResp(req);

		//非自己系统的 上送报文， 没有我们公众号的  openid
		if(req.getOpenid() == null || 0 == req.getOpenid().length()) {
			resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
			resp.setPayInfo(getOpenidUrl_callbackPay + order.getOrderNo());
			resp.setOrderNo(order.getOrderNo());
			return resp;
		}

		Map<String, String> paraMap = new HashMap<String, String>();
		paraMap.put("appid", APPID);
		if (req.getRemark() == null || 0 == req.getRemark().length()) {
			paraMap.put("body", order.getMerchOrderNo());
		} else {
			paraMap.put("body", req.getRemark());
		}

		if (null == req.getSub_appid() || 0 == req.getSub_appid().length()) {

		} else {
			paraMap.put("sub_appid", req.getSub_appid());
			paraMap.put("sub_openid", req.getSub_openid());
		}

		paraMap.put("mch_id", MERCHANT_NO);
		paraMap.put("sub_mch_id", order.getOtherMerchCode());
		paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
		paraMap.put("out_trade_no", order.getOrderNo());// 订单号
		paraMap.put("spbill_create_ip", "127.0.0.1");
		paraMap.put("total_fee", req.getAmount());
		paraMap.put("fee_type", order.getCoinType());
		paraMap.put("trade_type", "JSAPI");
		paraMap.put("openid", req.getOpenid());
		paraMap.put("notify_url", TRADE_NOTIFY_URL);// 此路径是微信服务器调用支付结果通知路径随意写
		String sign = WXPayUtil.generateSignature(paraMap, MERCHANT_KEY);
		paraMap.put("sign", sign);
		String xml = WXPayUtil.mapToXml(paraMap);
		String unifiedorder_url = TRADE_URL;
		String xmlStr = FSHttp.postString(unifiedorder_url, xml);
		FSLog.api.info("Send微信国际上游------->:" + unifiedorder_url + "\n" + xml + "\n");
		FSLog.api.info("recv微信国际上游------->:" + unifiedorder_url + "\n" + xmlStr + "\n");
		Map<String, String> mapstr = WXPayUtil.xmlToMap(xmlStr);
		String recvMysign = WXPayUtil.generateSignature(mapstr, MERCHANT_KEY);
		FSLog.api.info("返回的签名:" + mapstr.get("sign") + "," + "计算的签名:" + recvMysign);
		resp.setCodeAndMsg(Resp.InProcess.getCode(), Resp.InProcess.getMsg());
		resp.setPayInfo(JSONObject.toJSON(mapstr).toString());
		String prepay_id = null;
		if (mapstr != null && "SUCCESS".equals(mapstr.get("return_code"))
				&& "SUCCESS".equals(mapstr.get("result_code"))) {
			resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
			prepay_id = (String) mapstr.get("prepay_id");
			// 把数据传给前段页面， 执行微信的js调用即可调用 微信公众号支付的 支付页面s
			Map<String, String> payMap = new HashMap<String, String>();
			payMap.put("appId", APPID);
			payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
			payMap.put("nonceStr", WXPayUtil.generateNonceStr());
			payMap.put("signType", "MD5");
			payMap.put("package", "prepay_id=" + prepay_id);
			String paySign = WXPayUtil.generateSignature(payMap, MERCHANT_KEY);
			payMap.put("pg", "prepay_id=" + prepay_id);
			payMap.put("paySign", paySign);
			payMap.put("respCode", Resp.Success.getCode());
			payMap.put("coin_type", order.getCoinType());
			String pppJS = JSON.toJSONString(payMap);
			resp.setPayInfo(pppJS);
			resp.setOrderNo(order.getOrderNo());
		}
		return resp;
	}

	@Override
	public AppidWxgjPayResp wxgjmiropay(AppidWxgjPayReq req, TradeOrder order) throws Exception {
		AppidWxgjPayResp resp = new AppidWxgjPayResp(req);
		Map<String, String> paraMap = new HashMap<String, String>();
		paraMap.put("appid", APPID);
		if (req.getRemark() == null || 0 == req.getRemark().length()) {
			paraMap.put("body", order.getMerchOrderNo());
		} else {
			paraMap.put("body", req.getRemark());
		}
		if (null == req.getSub_appid() || 0 == req.getSub_appid().length()) {

		} else {
			paraMap.put("sub_appid", req.getSub_appid());
			paraMap.put("sub_openid", req.getSub_openid());
		}
		paraMap.put("mch_id", MERCHANT_NO);
		paraMap.put("sub_mch_id", order.getOtherMerchCode());
		paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
		paraMap.put("out_trade_no", order.getOrderNo());// 订单号
		paraMap.put("spbill_create_ip", "127.0.0.1");
		paraMap.put("total_fee", req.getAmount());
		paraMap.put("fee_type", order.getCoinType());
		paraMap.put("auth_code", req.getAuth_code());
		String sign = null;
		String xml = null;
		try {
			sign = WXPayUtil.generateSignature(paraMap, MERCHANT_KEY);
			paraMap.put("sign", sign);
			xml = WXPayUtil.mapToXml(paraMap);
		} catch (Exception e) {
			e.printStackTrace();
		}
		String unifiedorder_url = TRADE_URL_MICROPAY;
		FSLog.api.info("上送微信国际上游------>:" + unifiedorder_url + "\n" + xml + "\n");
		String xmlStr = FSHttp.postString(unifiedorder_url, xml);
		FSLog.api.info("接受微信国际返回------>:" + unifiedorder_url + "\n" + xmlStr + "\n");
		Map<String, String> mapstr = WXPayUtil.xmlToMap(xmlStr);
		String recvMysign = WXPayUtil.generateSignature(mapstr, MERCHANT_KEY);
		String signrecv = mapstr.get("sign");
		if (!recvMysign.equals(signrecv)) {
			FSLog.api.info("接受微信国际返回------>:" + "签名错误!!!!,返回的签名:" + signrecv + "\n" + "计算的签名:" + recvMysign);
		}
		resp.setCodeAndMsg(Resp.InProcess.getCode(), Resp.InProcess.getMsg());
		resp.setPayInfo(JSONObject.toJSON(mapstr).toString());
		resp.setOrderNo(order.getOrderNo());
		// 刷卡交易处理必须发一次查询，查询返回最终交易结果!
		return resp;
	}

	@Override
	public AppidWxgjPayResp wxgjqrcode(AppidWxgjPayReq req, TradeOrder order) throws Exception {
		AppidWxgjPayResp resp = new AppidWxgjPayResp(req);
		Map<String, String> paraMap = new HashMap<String, String>();
		paraMap.put("appid", APPID);
		if (req.getRemark() == null || 0 == req.getRemark().length()) {
			paraMap.put("body", order.getMerchOrderNo());
		} else {
			paraMap.put("body", req.getRemark());
		}
		if (null == req.getSub_appid() || 0 == req.getSub_appid().length()) {

		} else {
			paraMap.put("sub_appid", req.getSub_appid());
			paraMap.put("sub_openid", req.getSub_openid());
		}
		paraMap.put("mch_id", MERCHANT_NO);
		paraMap.put("sub_mch_id", order.getOtherMerchCode());
		paraMap.put("nonce_str", WXPayUtil.generateNonceStr());
		paraMap.put("out_trade_no", order.getOrderNo());// 订单号
		paraMap.put("spbill_create_ip", "127.0.0.1");
		paraMap.put("total_fee", req.getAmount());
		paraMap.put("fee_type", order.getCoinType());
		paraMap.put("trade_type", "NATIVE");
		String pid = req.getProduct_id();
		if (pid == null || 0 == pid.length()) {
			pid = req.getMerchOrderNo();
		}
		paraMap.put("product_id", pid);
		paraMap.put("notify_url", TRADE_NOTIFY_URL);
		String sign = WXPayUtil.generateSignature(paraMap, MERCHANT_KEY);
		paraMap.put("sign", sign);
		String xml = WXPayUtil.mapToXml(paraMap);
		String unifiedorder_url = TRADE_URL;
		String xmlStr = FSHttp.postString(unifiedorder_url, xml);
		FSLog.api.info("Send微信国际数据-------->:" + unifiedorder_url + "\n" + xml + "\n");
		FSLog.api.info("recv微信国际数据-------->:" + unifiedorder_url + "\n" + xmlStr + "\n");
		Map<String, String> mapstr = WXPayUtil.xmlToMap(xmlStr);
		String recvMysign = WXPayUtil.generateSignature(mapstr, MERCHANT_KEY);
		FSLog.api.info("返回的签名:" + mapstr.get("sign") + "," + "计算的签名:" + recvMysign);
		resp.setCodeAndMsg(Resp.InProcess.getCode(), Resp.InProcess.getMsg());
		resp.setPayInfo(JSONObject.toJSON(mapstr).toString());
		if (mapstr != null && "SUCCESS".equals(mapstr.get("return_code"))
				&& "SUCCESS".equals(mapstr.get("result_code"))) {
			resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
			String code_url = mapstr.get("code_url");
			resp.setPayInfo(code_url);
			resp.setOrderNo(order.getOrderNo());
		}
		return resp;
	}

	/*
	 * (non-Javadoc)退款申请
	 *
	 * @see com.bc.trade.channel.IChannel#refund(com.bc.trade.message.RefundReq,
	 * com.bc.trade.model.TradeOrder, com.bc.trade.model.TradeOrder)
	 */
	@SuppressWarnings("deprecation")
	@Override
	public RefundResp wxgjRefund(RefundReq req, TradeOrder refundOrder, TradeOrder orignOrder) throws Exception {
		RefundResp resp = new RefundResp(req);
		Map<String, String> map = new HashMap<>();
		map.put("appid", APPID);
		map.put("mch_id", MERCHANT_NO);
		map.put("sub_mch_id", orignOrder.getOtherMerchCode());
		map.put("nonce_str", WXPayUtil.generateNonceStr());
		map.put("transaction_id", orignOrder.getChannelOrderNo());
		map.put("out_trade_no", orignOrder.getOrderNo());
		map.put("out_refund_no", refundOrder.getOrderNo());
		map.put("total_fee", orignOrder.getTotalFee() + "");
		String  ss = URLEncoder.encode(req.getRemark(), "UTF-8");
		map.put("refund_desc", ss);// 退款原因
		map.put("refund_fee", req.getAmount());
		map.put("notify_url", refund_notify);

		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		String isok = "fail";
		FileInputStream instream = new FileInputStream(new File(sslck));
		try {
			keyStore.load(instream, "1497668372".toCharArray());
		} finally {
			instream.close();
		}
		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, MERCHANT_NO.toCharArray()).build();
//		// Allow TLSv1 protocol only
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
				SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
			String ssign = WXPayUtil.generateSignature(map, MERCHANT_KEY);
			map.put("sign", ssign);
			String xmlData = WXPayUtil.mapToXml(map);
			FSLog.api.info("trade.退款数据上送:" + xmlData);
			HttpPost httpget = new HttpPost(TRADE_REFUND_URL);
			StringEntity entity1 = new StringEntity(xmlData);
			entity1.setContentType("text/xml");
			httpget.setEntity(entity1);
			CloseableHttpResponse response = httpclient.execute(httpget);
			try {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					// System.out.println("Response content length: " + entity.getContentLength());
					BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
					String text;
					StringBuffer res = new StringBuffer();
					while ((text = bufferedReader.readLine()) != null) {
						res.append(text);
					}
					FSLog.api.info("trade.退款数据返回:" + res.toString());
					Map<String, String> resmap = WXPayUtil.xmlToMap(res.toString());
					String return_code = resmap.get("return_code");
					resp.setOriginalRespCode(Resp.InProcess.getCode());
					resp.setOriginalRespMsg(Resp.InProcess.getMsg());
					resp.setCodeAndMsg(Resp.InProcess.getCode(), Resp.InProcess.getMsg());

					if (!return_code.equals("SUCCESS")) {
						refundOrder.setRespCode("01");
						refundOrder.setRespMsg(return_code + ":" + resmap.get("return_msg"));
						isok = refundOrder.getRespMsg();

						resp.setOriginalRespCode(Resp.Fail.getCode());
						resp.setOriginalRespMsg(isok);
						resp.setCodeAndMsg(Resp.Fail.getCode(), isok);

					} else {
						String mysign = WXPayUtil.generateSignature(resmap, MERCHANT_KEY);
						String sign = resmap.get("sign");
						boolean compareSign = mysign.equals(sign);
						if (compareSign) {
							String result_code = resmap.get("result_code");
							if (result_code.equals("SUCCESS")) {
								FSLog.api.info("2.退款申请处理完成:" + res.toString());
								isok = "ok";
								refundOrder.setPayTime(FSDate.getDateTime());
								refundOrder.setChannelOrderNo(resmap.get("refund_id"));
								refundOrder.setOrderStatus(OrderStatus.DoRefund.getValue());
								refundOrder.setRespCode(Resp.Success.getCode());
								refundOrder.setRespMsg(result_code + ":" + resmap.get("err_code_des"));

								resp.setOriginalRespCode(Resp.Success.getCode());
								resp.setOriginalRespMsg(Resp.Success.getMsg());
								resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
							} else {
								refundOrder.setRespCode(Resp.Fail.getCode());
								String err_code = resmap.get("err_code");
								refundOrder.setRespMsg(err_code + ":" + resmap.get("err_code_des"));
								isok = refundOrder.getRespMsg();
								resp.setOriginalRespCode(Resp.Fail.getCode());
								resp.setOriginalRespMsg(isok);
								resp.setCodeAndMsg(Resp.Fail.getCode(), isok);
							}
						} else {
							refundOrder.setRespCode("02");
							refundOrder.setRespMsg("签名验证错误!!!!");
							isok = "签名验证错误!!!!";

							resp.setOriginalRespCode(Resp.Fail.getCode());
							resp.setOriginalRespMsg(isok);
							resp.setCodeAndMsg(Resp.Fail.getCode(), isok);
						}
					}

				}
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		return resp;
	}

	/*
	 * 退款查询
	 */
	@SuppressWarnings("static-access")
	@Override
	public RefundResp wxgjRefundQuery(RefundReq req, TradeOrder orignOrder) throws Exception {
		Map<String, String> map = new HashMap<>();
		RefundResp resp = new RefundResp(req);
		map.put("appid", APPID);
		map.put("mch_id", MERCHANT_NO);
		map.put("sub_mch_id", orignOrder.getOtherMerchCode());
		map.put("nonce_str", WXPayUtil.generateNonceStr());
		map.put("out_trade_no", orignOrder.getOrderNo());

		try {
			String ssign = WXPayUtil.generateSignature(map, MERCHANT_KEY);
			map.put("sign", ssign);
			String xmlData = WXPayUtil.mapToXml(map);
			FSLog.api.info("00trade.退款查询数据上送:" + xmlData);
			String res = FSHttp.postString("https://api.mch.weixin.qq.com/pay/refundquery", xmlData);
			FSLog.api.info("01trade.退款查询数据返回:" + res);
			Map<String, String> resmap = WXPayUtil.xmlToMap(res);
			String return_code = resmap.get("return_code");
			String result_code = resmap.get("result_code");

			int refund_count = Integer.parseInt(resmap.get("refund_count"));

			if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
				int allRefFee = 0;
				for (int i = 0; i < refund_count; i++) {
					String out_refund_no = resmap.get("out_refund_no_" + i);
					String refund_id = resmap.get("refund_id_" + i);
					String refund_status = resmap.get("refund_status_" + i);
					String refund_fee = resmap.get("refund_fee_" + i);

					// 找到对应的退款订单信息
					TradeOrder refundOrder = TradeOrder.dao.selectByOrderNoForUpdate(out_refund_no);
					if (refundOrder == null) {
						FSLog.api.info(out_refund_no + "此退款订单不存在!!!" + "02trade.退款查询数据返回:" + xmlData);
						// 创建一笔退款单号--此情况出现在没有使用trade系统， 而是直接使用微信系统退款的情况
						req.setMerchOrderNo(out_refund_no);
						req.setRefundOrderNo(orignOrder.getOrderNo());
						refundOrder = TradeOrder.dao.createRefund(req, orignOrder);
						refundOrder.save();
					}

					if ("SUCCESS".equals(refund_status)) {
						allRefFee += Integer.parseInt(refund_fee);// 总的退款金额
						// 找到原交易订单，状态改成"已退款" RF

						if (refund_id.equals(refundOrder.getChannelOrderNo())
								&& OrderStatus.Refund.getValue().equals(refundOrder.getOrderStatus())) {

						} else {
							refundOrder.setOrderStatus(OrderStatus.Refund.getValue());
							refundOrder.setChannelOrderNo(refund_id);
							refundOrder.update();
						}
					} else if ("REFUNDCLOSE".equals(refund_status)) {
						FSLog.api.info(out_refund_no + "此退款订单已经关闭!!!" + "退款金额:" + refund_fee + "," + "02trade.退款查询数据返回:"
								+ xmlData);

						refundOrder.setOrderStatus(OrderStatus.Cancle.getValue());
						refundOrder.setChannelOrderNo(refund_id);
						refundOrder.update();
					}
				}
				if (allRefFee > 0) {
					TradeStrategy ts = null;
					// 交易策略
					ts = TradeStrategy.dao.selectFromRedis(orignOrder.getMerchCode(), orignOrder.getPayType());
					//虚账也需要减掉 对应的退款金额
					orignOrder.setAmount(orignOrder.getTotalFee() - allRefFee);// 原订单交易金额减掉退款总金额
					if(orignOrder.getAmount() == 0) {
						orignOrder.setMerchFee(0);//全额退款后再设置手续费为0
					}else {
						orignOrder.setMerchFee(
						new CalcFeeService().getFee(orignOrder.getAmount(), ts.getMerchFeeId()));
					}
					orignOrder.update();
					AccountBalanceChangeResp virResp =
					accountService.subMoney(false, ts.getChannelCode(), orignOrder.getMerchCode(), allRefFee);

					if(!"SUCCESS".equals(virResp.getRespCode())) {
						FSLog.api.info("ERROR----手工调整虚账--" + "渠道:" + ts.getChannelCode() + ";订单号:" +orignOrder.getOrderNo()+
								"商户号:" + orignOrder.getMerchCode() + "减去虚账结果:" +
						JSON.toJSONString(virResp));
					}
					FSLog.api.info("渠道:" + ts.getChannelCode() + ";订单号:" +orignOrder.getOrderNo()+
							"商户号:" + orignOrder.getMerchCode() + "减去虚账结果:" +
					JSON.toJSONString(virResp));

				}
				resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
				resp.setOriginalRespCode(Resp.Success.getCode());
				resp.setOriginalRespMsg(Resp.Success.getMsg());
			} else {
				String err_code = resmap.get("err_code");
				String err_code_des = resmap.get("err_code_des");

				resp.setCodeAndMsg(Resp.Fail.getCode(), err_code + err_code_des);
				resp.setOriginalRespCode(Resp.Fail.getCode());
				resp.setOriginalRespMsg(err_code + err_code_des);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		return resp;
	}

	@Override
	public  WxgjClearingResp wxgjGetClearingData(WxgjClearingReq req, TradeStrategy ts) throws Exception{
		Map<String, String> map = new HashMap<>();
		WxgjClearingResp resp = new WxgjClearingResp(req);
		map.put("appid", APPID);
		map.put("mch_id", MERCHANT_NO);
		map.put("sub_mch_id", ts.getChannelSubMerchCode());
		map.put("nonce_str", WXPayUtil.generateNonceStr());
		map.put("usetag", "1");
		map.put("offset", "0");
		map.put("limit", "10");
		map.put("date_start", req.getDate_start());
		map.put("date_end", req.getDate_end());

		try {
			String ssign = WXPayUtil.generateSignature(map, MERCHANT_KEY);
			map.put("sign", ssign);
			String xmlData = WXPayUtil.mapToXml(map);
			FSLog.weixin.info("\n\n\n\n\n----start----------------------------------------------------------"
					+ "00trade.微信结算资金查询数据上送:" + xmlData);
			String res = FSHttp.postString("https://api.mch.weixin.qq.com/pay/settlementquery", xmlData);
			FSLog.weixin.info("01trade.微信结算资金查询数据返回:" + res);
			//Map<String, String> resmap = WXPayUtil.xmlToMap(res);
			//String return_code = resmap.get("return_code");
			//String result_code = resmap.get("result_code");

			 /* 第一种方法，使用JSON-JAVA提供的方法 */
	        //将xml转为json
			org.json.JSONObject xmlJSONObj = org.json.XML.toJSONObject(res);
			org.json.JSONObject xmlJSONObj02 = xmlJSONObj.getJSONObject("xml");
	        //设置缩进
	        //String jsonPrettyPrintString = xmlJSONObj.toString(4);
	        //输出格式化后的json
	        //System.out.println(jsonPrettyPrintString);
	        //FSLog.weixin.info("02trade.微信结算资金查询数据返回JSON:" + jsonPrettyPrintString);
			FSLog.weixin.info("02trade.微信结算资金查询数据返回:" + xmlJSONObj02.toString(4));

			String return_code = xmlJSONObj02.getString("return_code");
			String result_code = xmlJSONObj02.getString("result_code");

			Integer record_num = xmlJSONObj02.getInt("record_num");
			if("SUCCESS".equals(result_code) && "SUCCESS".equals(return_code) &&
					record_num!=null && record_num > 0) {

				for(int i = 0; i < record_num; i++) {
					org.json.JSONObject resmap = xmlJSONObj02.getJSONObject("setteinfo_" + i);
					FSLog.weixin.info("第"+ i +  "记录----微信结算资金查询数据返回:" + resmap.toString(4));
					resp.setDate_end(resmap.optString("date_end"));
					resp.setDate_start(resmap.optString("date_start"));
					resp.setDate_settlement(resmap.optString("date_settlement"));
					resp.setFbatchno(resmap.optString("fbatchno"));
					resp.setPay_fee(resmap.optString("pay_fee"));
					resp.setPay_net_fee(resmap.optString("pay_net_fee"));
					resp.setPoundage_fee(resmap.optString("poundage_fee"));
					resp.setRefund_fee(resmap.optString("refund_fee"));
					resp.setSettlement_fee(resmap.optString("settlement_fee"));
					resp.setSettlementfee_type(resmap.optString("settlementfee_type"));
					resp.setUnsettlement_fee(resmap.optString("unsettlement_fee"));

					WxClear.createClear(resp, ts.getChannelSubMerchCode());
				}
				resp.setCodeAndMsg(Resp.Success.getCode(), "success");

			}else {
				String err_code = xmlJSONObj02.optString("err_code");
				String err_code_des = xmlJSONObj02.optString("err_code_des");
				resp.setCodeAndMsg(Resp.Fail.getCode(), err_code+err_code_des);
			}
		}catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			resp.setCodeAndMsg(Resp.Fail.getCode(), e.toString());
		}

		FSLog.weixin.info("\n\n\n\n\n----end----------------------------------------------------------");
		return resp;
	}



}
